home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
tex
/
sed15.zip
/
SEDEXEC.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-09-27
|
20KB
|
539 lines
/*
* sedexec.c -- execute compiled form of stream editor commands
*
* The single entry point of this module is the function execute(). It may take
* a string argument (the name of a file to be used as text) or the argument
* NULL which tells it to filter standard input. It executes the compiled
* commands in cmds[] on each line in turn. The function command() does most
* of the work. Match() and advance() are used for matching text against
* precompiled regular expressions and dosub() does right-hand-side
* substitution. Getline() does text input; readout() and smemcmp() are
* output and string-comparison utilities.
*
* ==== Written for the GNU operating system by Eric S. Raymond ====
* v1.2, 14 Jul 91
* From: mdlawler@bsu-cs.bsu.edu (Michael D. Lawler)
* Change the line in sedexec.c from
* static int delete;
* to
* static int delete = TRUE;
* and let me know if it still compiles ok under TurboC 2.0.
* I made this change which was suggested by Mark Adler
* and it made sed work fine under BC++ 2.0.
*
* Toad Hall: Compiles just fine in TC 2.0.
*
* v1.1, 19 Jun 91
* Toad Hall Tweak for TC v2.0
* See VERSION.NOT for details
* modified September 91 by hh see notes in sedcomp.c
*/
#ifdef OTHER /*hh 14*/
#include "compiler.h"
#include "debug.h"
#endif
#ifdef LATTICE
#define void int
#endif
#include <stdio.h> /* {f}puts, {f}printf, getc/putc, f{re}open, fclose */
#include <ctype.h> /* for isprint(), isdigit(), toascii() macros */
#include "sed.h" /* command type structures & miscellaneous* constants */
#ifdef __TURBOC__ /* v1.1 */
#include <string.h>
#include <stdlib.h> /* exit() */
static char *getline(register char *buf);
static int selected(sedcmd *ipc);
static void command(sedcmd *ipc);
static void readout(void);
static int match(char *expbuf, int gf);
static int advance(register char *lp, register char *ep);
static void dosub(char *rhsbuf);
static char *place(char *asp,char *al1,char *al2);
static void listto(register char *p1, FILE *fp);
static int substitute(sedcmd *ipc);
/* v1.1 renamed this so it wouldn't conflict with TC's memcmp() */
static int smemcmp(register char *a, register char *b, int count);
#else /* !PROTO */
extern char *strcpy(); /* used in dosub */
char *getline(); /* input-getting functions */
void command(), readout();
void dosub(); /* for if we find a match */
char *place();
#endif /* ?PROTO */
/***** shared variables imported from the main ******/
/* main data areas */
extern char linebuf[]; /* current-line buffer */
extern sedcmd cmds[]; /* hold compiled commands */
extern long linenum[]; /* numeric-addresses table */
/* miscellaneous shared variables */
extern int nflag; /* -n option flag */
extern int eargc; /* scratch copy of argument count */
extern sedcmd *pending; /* ptr to command waiting to be executed */
extern char bits[]; /* the bits table */
#define MAXHOLD MAXBUF /* size of the hold space */
#define GENSIZ MAXBUF /* maximum genbuf size */
#define TRUE 1
#define FALSE 0
#define JUMPLIMIT 50 /*max branches before inf loop*/
#define ABORT2(msg,arg) (fprintf(stderr,msg,arg),exit(2))
#define ISWCHAR(c) (isalnum(c)||c=='_')
#define Copy(to,from,ep) {char *it=to,*ix=from;while(*it++=*ix++);ep=it-1;}
static char INFLOOP[]= "sed: infinite branch loop at line %ld\n";
static char LTLMSG[] = "sed: line too long at line %ld\n";
static char FILEBAD[]= "sed: cannot open %s\n";
static char REBAD[]= "sed: RE bad code %x\n";
static char APPERR[]= "sed: too many appends after line %ld\n";
static char APPLNG[]= "sed: append too long after line %ld\n";
static char READERR[]= "sed: too many reads after line %ld\n";
static char *spend; /* current end-of-line-buffer pointer */
static long lnum = 0L; /* current source line number */
/* append buffer maintenance */
static sedcmd *appends[MAXAPPENDS]; /* array of ptrs to a,i,c commands */
static sedcmd **aptr = appends; /* ptr to current append */
/* genbuf and its pointers and misc pointers*/
static char genbuf[GENSIZ];
static long pcnt[MAXPLUS]; /*holder for count downs*/
/* command-logic flags */
static int lastline; /* do-line flag */
static int jump, jumpcnt; /* jump set and loop counter */
static int delete = FALSE; /* delete command flag *//*hh 2*/
static int cdswitch=FALSE; /*in midst of D command*/
/* tagged-pattern tracking */
static char *bracend[MAXTAGS+1]; /* tagged pattern start pointers */
static char *brastart[MAXTAGS+1]; /* tagged pattern end pointers */
/* execute the compiled commands in cmds[] on a file */
void execute(file) char *file;{ /* name of text source file to be edited */
register sedcmd *ipc; /* ptr to current command */
if (file&&!freopen(file, "rt", stdin)) ABORT2(FILEBAD,file);
/* here's the main command-execution loop */
while(pending||cdswitch||(spend=getline(linebuf))){ /* v1.5*/
ipc =pending? pending:cmds;
delete=jumpcnt=0;cdswitch=FALSE;
while(!delete&&ipc->command){
if(pending||selected(ipc))command(ipc);
if(jump){
jump=FALSE;
if(++jumpcnt>=JUMPLIMIT)ABORT2(INFLOOP,lnum);
ipc=ipc->u.link;}
else ipc++;}
if(pending)break;
/* we've now done all modification commands on the line */
PASS("execute(): output");
if (!nflag && !delete) puts(linebuf);
/* if we've been set up for append, emit the text from it */
if (aptr > appends)readout();
PASS("execute(): end main loop");}
PASS("execute(): end execute");}
static int selected(ipc)
sedcmd *ipc;
/* is current command selected */
{/*hh 10*/
char *p1=ipc->addr1;
char *p2=ipc->addr2;
int ans,first=FALSE;
if(!p1)return !ipc->flags.allbut;
if( (ans=ipc->flags.inrange) != 0) ; /* v1.4 */
else if (*p1 == CEND) ans=lastline;
else if (*p1==CLNUM)
first=ipc->flags.inrange=ans=lnum==linenum[*(unsigned char*)(p1+1)];
else first=ipc->flags.inrange=ans=match(p1, 0);
if ( ((ipc->flags.inrange&=(p2!=0)) != 0)
&& (*p2!=CEND)
) {
if(*p2==CLNUM)ipc->flags.inrange=(lnum<linenum[*(unsigned char*)(p2+1)]);
else if(*p2==CPLUS){
if(first) pcnt[p2[2]]=linenum[*(unsigned char*)(p2+1)];
ipc->flags.inrange=((--pcnt[p2[2]])>=0);}
else ipc->flags.inrange=!match(p2, 0);}
return ans^ipc->flags.allbut;}
/* match RE at expbuf against linebuf; if gf set, copy linebuf from genbuf */
static int match(expbuf, gf) char *expbuf;int gf;{/* gf set on recall */
char c, *p1=gf?bracend[0]:linebuf; int i;
for (i=1;i<MAXTAGS+1;i++)brastart[i]=bracend[i]=linebuf;
if(gf&&*expbuf) return FALSE; /*no repeats on anchored match*/
if (*expbuf++) {
brastart[0]= p1;
if (*expbuf==CCHR &&expbuf[1] != *p1) /* 1st char is wrong */
return (FALSE); /* so fail */
return (advance(p1, expbuf));} /* else try to match rest */
/* quick check for 1st character if it's literal */
if (*expbuf==CCHR) {c = expbuf[1]; /* get search character */
do { if (*p1 != c)continue; /* scan the source string */
if (advance(brastart[0]=p1,expbuf)) /* match the rest */
return 1;
} while (*p1++);
return (FALSE);} /* didn't find that first char */
/* else try for unanchored match of the pattern */
do {if (advance(brastart[0]=p1,expbuf))return 1;
} while (*p1++);
/* if got here, didn't match either way */
return (FALSE);}
/* attempt to advance match pointer by one pattern element */
static int advance(lp, ep) char *lp, *ep; {/* source, RE*/
char *curlp; /* save ptr for closures */
char c; /* scratch character holder */
char *bbeg,*tep;
int ct,i1,i2; /* scratch integer holders */
while((c=*ep++)!=CEOF) switch(c){
case CCHR: /* literal character */
if (*ep++ == *lp++) break; /* if chars are equal */
return (FALSE); /* else return false */
case CBOW: /*at the begining of a word*/
if(ISWCHAR(*lp)&&!ISWCHAR(lp[-1]))break; /*at word start*/
return (FALSE);
case CEOW: /*at the end of a word*/
if(!ISWCHAR(*lp)&&